package com.sangeng.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sangeng.constant.SystemConstants;
import com.sangeng.domain.core.ResponseResult;
import com.sangeng.domain.dto.ArticleInsertDto;
import com.sangeng.domain.dto.ArticleListDto;
import com.sangeng.domain.dto.ArticleListQueryDto;
import com.sangeng.domain.dto.ArticleUpdateDto;
import com.sangeng.domain.entity.Article;
import com.sangeng.domain.entity.ArticleTag;
import com.sangeng.domain.entity.Category;
import com.sangeng.domain.vo.*;
import com.sangeng.mapper.ArticleMapper;
import com.sangeng.service.ArticleService;
import com.sangeng.service.ArticleTagService;
import com.sangeng.service.CategoryService;
import com.sangeng.utils.BeanUtil;
import com.sangeng.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService{

    @Autowired
    CategoryService categoryService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ArticleTagService articleTagService;

    @Override
    public ResponseResult hotArticleList() {
        // lambda方式查询
        LambdaQueryWrapper<Article> articleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        articleLambdaQueryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL)
                .orderByDesc(Article::getViewCount);
        // 显示10条数据
        Page<Article> page = new Page<>(1,10);
        List<Article> articles = page(page, articleLambdaQueryWrapper).getRecords();
        List<HotArticleVo> articleVos = BeanUtil.copyBeanList(articles, HotArticleVo.class);
        // 更新viewCount信息
        articleVos.forEach(articleVo -> {
            Integer cacheMapValue = redisCache.getCacheMapValue("article:viewCount", articleVo.getId().toString());
            articleVo.setViewCount(cacheMapValue.longValue());
        });
        return ResponseResult.okResult(articleVos);
    }

    @Override
    public ResponseResult articleList(ArticleListDto articleListDto) {
        // 如果有categoryId 就在查询时要传入参数
        // 查询正式发布的文章
        // 对isTop进行降序排序
        // 进行分页查询
        Page<Article> page = new Page<>(articleListDto.getPageNum(),articleListDto.getPageSize());
        Page<Article> articlePage = page(page, new LambdaQueryWrapper<Article>()
                .eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL)
                .eq(!Objects.isNull(articleListDto.getCategoryId()) && articleListDto.getCategoryId() > 0, Article::getCategoryId, articleListDto.getCategoryId())
                .orderByDesc(Article::getIsTop)
        );
        // 封装成vo
        List<ArticleVo> articleVos = BeanUtil.copyBeanList(articlePage.getRecords(), ArticleVo.class);
        // 从redis中更新viewCount
        articleVos.forEach(articleVo -> {
            Integer cacheMapValue = redisCache.getCacheMapValue("article:viewCount", articleVo.getId().toString());
            articleVo.setViewCount(cacheMapValue.longValue());
        });
        // 将categoryId转成categoryName
        List<Long> categoryIds = articleVos.stream().map(ArticleVo::getCategoryId).toList();
        List<Category> categorys = new ArrayList<>();
        Map<Long, String> categoryNames = new HashMap<>();
        if(!categoryIds.isEmpty()) {
            categorys = categoryService.listByIds(categoryIds);
        }
        if(!Objects.isNull(categorys)){
            categoryNames = categorys.stream()
                    .collect(Collectors.toMap(Category::getId, Category::getName));
        }
        for(ArticleVo articleVo : articleVos){
            articleVo.setCategoryName(categoryNames.get(articleVo.getCategoryId()));
        }

        PageVo pageVo = new PageVo(articleVos, articlePage.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public ResponseResult getArticleDetialsById(Long id) {
        Article article = getById(id);
        Category category = categoryService.getById(article.getCategoryId());
        ArticleDetailsVo articleVo = BeanUtil.copyBean(article, ArticleDetailsVo.class);
        // 更新viewCount
        Integer cacheMapValue = redisCache.getCacheMapValue("article:viewCount", id.toString());
        articleVo.setViewCount(cacheMapValue.longValue());
        if(Objects.nonNull(category))articleVo.setCategoryName(category.getName());
        return ResponseResult.okResult(articleVo);
    }

    @Override
    public ResponseResult updateViewCount(Long id) {
        redisCache.incrementMapValue("article:viewCount", id.toString(), 1);
        return ResponseResult.okResult();
    }

    @Override
    public void updateViewCountToDataBase() {
        Map<String, Object> viewCountMap = redisCache.getCacheMap("article:viewCount");
        List<Article> articles = viewCountMap.entrySet().stream()
                .map(entry -> new Article(Long.valueOf(entry.getKey()), Long.valueOf(entry.getValue().toString())))
                .toList();
        updateBatchById(articles);
    }

    @Transactional
    @Override
    public ResponseResult insertArticle(ArticleInsertDto insertArticle) {
        Article article = BeanUtil.copyBean(insertArticle, Article.class);
        article.setViewCount(0L);
        save(article);
        List<ArticleTag> articleTags = insertArticle.getTags().stream()
                .map(tagId -> new ArticleTag(article.getId(), tagId)).toList();
        articleTagService.saveBatch(articleTags);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult adminArticleList(ArticleListQueryDto articleListDto) {
        // 封装查询参数
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(!Objects.isNull(articleListDto.getTitle()), Article::getTitle, articleListDto.getTitle());
        queryWrapper.like(!Objects.isNull(articleListDto.getSummary()), Article::getSummary, articleListDto.getSummary());

        // 封装分页查询参数
        Page<Article> page = new Page<>(articleListDto.getPageNum(),articleListDto.getPageSize());

        // 执行查询并封装到指定Vo
        Page<Article> articlePage = page(page, queryWrapper);
        List<AdminArticleVo> adminArticleVos = BeanUtil.copyBeanList(articlePage.getRecords(), AdminArticleVo.class);

        // 返回分页数据
        return ResponseResult.okResult(new PageVo(adminArticleVos, articlePage.getTotal()));
    }

    @Override
    public ResponseResult getAdminArticleById(Long id) {
        Article article = getById(id);
        ArticleUpdateVo articleUpdateVo = BeanUtil.copyBean(article, ArticleUpdateVo.class);

        // 查询文章标签
        LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleTag::getArticleId, id);
        List<Long> tags = articleTagService.list(queryWrapper).stream()
                .map(ArticleTag::getTagId).toList();
        articleUpdateVo.setTags(tags);
        return ResponseResult.okResult(articleUpdateVo);

    }

    @Transactional
    @Override
    public ResponseResult updateArticle(ArticleUpdateDto updateArticle) {
        // 更新文章内容
        Article article = BeanUtil.copyBean(updateArticle, Article.class);
        updateById(article);

        // 更新文章标签
        LambdaQueryWrapper<ArticleTag> query = new LambdaQueryWrapper<ArticleTag>().eq(ArticleTag::getArticleId, updateArticle.getId());
        articleTagService.remove(query);
        List<ArticleTag> tags = updateArticle.getTags().stream()
                .map(tagId -> new ArticleTag(updateArticle.getId(), tagId))
                .toList();
        articleTagService.saveBatch(tags);
        return ResponseResult.okResult();
    }

    @Transactional
    @Override
    public ResponseResult deleteById(Long id) {
        // 逻辑删除
        removeById(id);
        // 删除文章标签
        LambdaQueryWrapper<ArticleTag> query = new LambdaQueryWrapper<ArticleTag>().eq(ArticleTag::getArticleId, id);
        articleTagService.remove(query);
        return ResponseResult.okResult();
    }
}
